package com.szxx.suit.fourtakepair;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.szxx.constant.DdzCardTypes;
import com.szxx.constant.DdzCardConstant;
import com.szxx.domain.Card;
import com.szxx.domain.Cards;
import com.szxx.domain.DdzCard;
import com.szxx.suit.AbstractSuitTerm;
import com.szxx.suit.AbstractSuitType;
import com.szxx.suit.DdzAnalysisResult;
import com.szxx.suit.DdzSuitAnalyzer;
import com.szxx.suit.DdzTypeUtil;
import com.szxx.suit.bomb.BombTypeAnalyzer;
import com.szxx.suit.pair.PairTypeAnalyzer;

/**
 * 四带两对牌型 <br>
 *
 * @author Ambrose
 */
@Component
public class FourTakePairTypeAnalyzer extends DdzSuitAnalyzer {
	
	@Autowired
	private PairTypeAnalyzer pairTypeAnalyzer;

	@Override
	public AbstractSuitType getSuitType() {
		return DdzCardTypes.FOUR_TAKE_PAIR;
	}

	/** 元组数量 */
	private static int TUPLE_SIZE = 8;
	
	@Override
	protected boolean doCheckRule(Cards cards, AbstractSuitTerm term, DdzAnalysisResult result) {
		if (result.getCardNum() == TUPLE_SIZE) { // 八张牌，考虑 44443355 55556666
			if (result.getNoneLaziValueCounter().hasJoker()) { // 四带两对不能出现王
				return false;
			}
			if (result.isAllCardLazi()) { // 全是癞子
				return false;
			}
			List<Integer> allValues = result.getNoneLaziValueCounter().getAllValues(); // 非癞子的点数
			int allValueSize = allValues.size();
			if (allValueSize > 3) { // 四带两对牌型最多只有3种点数
				return false;
			} else { // 只有1种,2种或3种点数的情况
				int laiziCardNum = result.getLaziCardNum();
				if (laiziCardNum >= 4) { // 一定可以组成四带两对
					return true;
				} else { // 癞子数小于三个
					if (allValueSize == 2) { // 两种点数
						return true;
					} else { // 三种点数  排除点数分布 133 和 134 牌型
						int count = 0; 
						for (Integer value : allValues) {
							int valueNum = result.getNoneLaziValueCounter().getValueCount(value);
							if (valueNum >= 3) {
								count++;
							}
						}
						if (count >= 2) {
							return false;
						} else {
							return true;
						}
					}
				}
			}
		} else {
			return false;
		}
	}
	
	@Override
	protected List<Cards> doAnalysizeLaizi(Cards cards, AbstractSuitTerm term, boolean onlyMaxValue) {
		List<Cards> cardsResult = new LinkedList<Cards>();
		DdzAnalysisResult result = (DdzAnalysisResult) cards.getResult();
		List<Integer> allValues = result.getNoneLaziValueCounter().getAllValues(); // 非癞子的点数
		int allValueSize = allValues.size();
		int laiziCardNum = result.getLaziCardNum();
		// 只有2种或3种点数的情况
		if (laiziCardNum >= 4) { // 一定可以组成四带两对
			if (laiziCardNum == 7 || laiziCardNum == 6) { // 3******* 34******
				makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
			} else if (laiziCardNum == 5) {
				if (allValueSize == 1 || allValueSize == 2) { // 388******
					makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
				} else { // 345******
					makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
				}
			} else { // 四个癞子 
				if (allValueSize == 1) {
					makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
				} else if (allValueSize == 2) { // 两种点数 2333**** 2233****
					List<Integer> count_3_values = result.getNoneLaziValueCounter().getValuesInCount(3);
					if (count_3_values.size() > 0) { // 2333****
						makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
					} else { // 2233**** 可以组成任意牌型
						makeItInAllValues(cards, term, onlyMaxValue, cardsResult);
					}
				} else { // 三种点数 2344****
					makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
				}
			}
		} else { // 癞子数小于三个 
			makeItInSomeValues(cards, term, onlyMaxValue, cardsResult);
		}
		return cardsResult;
	}

	/**
	 * 在已知值中寻找四带两对
	 * 
	 * @param cards
	 * @param term
	 * @param onlyMaxValue
	 * @param cardsResult
	 */
	private void makeItInSomeValues(Cards cards, AbstractSuitTerm term, boolean onlyMaxValue, List<Cards> cardsResult) {
		DdzAnalysisResult result = (DdzAnalysisResult) cards.getResult();
		List<Card> laiziCardList = new ArrayList<Card>(cards.subList(result.getCardNum() - result.getLaziCardNum(), result.getCardNum()));
		List<Integer> allValues = result.getNoneLaziValueCounter().getAllValues(); // 非癞子的点数
		int laiziCardNum = result.getLaziCardNum();
		for (int i = allValues.size() - 1; i >= 0; i--) { 
			int i_valueTemp = allValues.get(i);
			result.setSortFirstValue(i_valueTemp);
			int i_valueTempNum = result.getNoneLaziValueCounter().getValueCount(i_valueTemp);
			int i_needLaiziNum = 4 - i_valueTempNum;
			if (i_needLaiziNum <= laiziCardNum) {
				int laiziCardIndex = 0;
				for (int i_laiziIndex = 0; i_laiziIndex < i_needLaiziNum; i_laiziIndex++) {
					((DdzCard)laiziCardList.get(laiziCardIndex++)).changeCard(i_valueTemp); 
				}
				for (int j = allValues.size() - 1; j >= 0; j--) {
					int j_valueTemp = allValues.get(j);
					if (j_valueTemp != i_valueTemp) { // 其余赋值needLaizinum_j个癞子
						int j_valueTempNum = result.getNoneLaziValueCounter().getValueCount(j_valueTemp);
						if (j_valueTempNum % 2 != 0) { // 遇单补齐
							i_needLaiziNum += 1;
							if (i_needLaiziNum <= laiziCardNum) {
								((DdzCard)laiziCardList.get(laiziCardIndex++)).changeCard(j_valueTemp);
							} else {
								break;
							}
						}
					}
				}
				// 如果有剩下补齐成对儿
				for (int j = laiziCardIndex; j < laiziCardNum; j++) {
					((DdzCard)laiziCardList.get(j)).changeCard(laiziCardList.get(laiziCardIndex).getNumber());
				}
				if (i_needLaiziNum <= laiziCardNum) {
					Cards cardsCopy = cards.clone();
					analysize(cardsCopy, term);
					cardsResult.add(cardsCopy);
					if (onlyMaxValue) {
						break; // 取完最大一组就跳出
					}
				}
			}
		}
	}

	/**
	 * 遍历所有值寻找四带两对
	 * 
	 * @param cards
	 * @param term
	 * @param onlyMaxValue
	 * @param cardsResult
	 */
	private void makeItInAllValues(Cards cards, AbstractSuitTerm term, boolean onlyMaxValue, List<Cards> cardsResult) {
		DdzAnalysisResult result = (DdzAnalysisResult) cards.getResult();
		List<Card> laiziCardList = new ArrayList<Card>(cards.subList(result.getCardNum() - result.getLaziCardNum(), result.getCardNum()));
		List<Integer> allValues = result.getNoneLaziValueCounter().getAllValues(); // 非癞子的点数
		int laiziCardNum = result.getLaziCardNum();
		for (int valueTemp = DdzCardConstant.NUMBER_2_VALUE; valueTemp >= DdzCardConstant.NUMBER_3_VALUE; valueTemp--) {
			result.setSortFirstValue(valueTemp);
			int valueTempNum = result.getNoneLaziValueCounter().getValueCount(valueTemp);
			int laiziCardIndex = 0;
			int needLaziNum = 4 - valueTempNum;
			for (int i = 0; i < needLaziNum; i++) {
				((DdzCard)laiziCardList.get(laiziCardIndex++)).changeCard(valueTemp);
			}
			for (int j = allValues.size() - 1; j >= 0; j--) {
				int j_valueTemp = allValues.get(j);
				if (j_valueTemp != valueTemp) {
					int j_valueTempNum = result.getNoneLaziValueCounter().getValueCount(j_valueTemp);
					if (j_valueTempNum % 2 != 0) { // 遇单补齐
						((DdzCard)laiziCardList.get(laiziCardIndex++)).changeCard(j_valueTemp);
					}
				}
			}
			// 如果有剩下补齐成对儿
			for (int j = laiziCardIndex; j < laiziCardNum; j++) {
				((DdzCard)laiziCardList.get(j)).changeCard(
						laiziCardList.get(laiziCardIndex).getNumber());
			}
			Cards cardsCopy = cards.clone();
			analysize(cardsCopy, term);
			cardsResult.add(cardsCopy);
			if (onlyMaxValue) {
				break; // 取完最大一组就跳出
			}
		}
	}
	
	@Override
	protected boolean containsPossibleCards(Cards handCards, AbstractSuitTerm term) {
		DdzAnalysisResult result = (DdzAnalysisResult) handCards.getResult();
		return result.getCardNum() - result.getJokerCardNum() >= TUPLE_SIZE;
	}
	
	/** 最多使用癞子的数量 */
	private static int MAX_USE_LAIZI_CARD_NUM = 6;
	
	/** 防重复判定的比例值 参照 int key = count_3_value * TUPLE_WEIGHT + count_1_value_a + count_1_value_b; */
	private static int TUPLE_WEIGHT = 1000000;
	
	/** 癞子权重，区分癞子变成的5 和 原本就是5 */
	private static int LAIZI_WEIGHT = 1000;
	
	@Override
	protected List<Cards> doListPossibleCards(Cards handCards, AbstractSuitTerm term) {
		List<Cards> cardsResult = new LinkedList<Cards>();
		// 非癞子部分
		DdzAnalysisResult result = (DdzAnalysisResult) handCards.getResult();
		List<Card> noneLaiziCardList = handCards.subList(0, result.getNoneCardNum());
		Cards noneLaiziCards = DdzTypeUtil.createCardsCopy(noneLaiziCardList);
		noneLaiziCards.setResult(handCards.getResult().clone());
		DdzAnalysisResult noneLaiziCardsResult = (DdzAnalysisResult) noneLaiziCards.getResult();
		noneLaiziCardsResult.collectNumber(noneLaiziCards, term);
		// 癞子部分
		List<Card> laiziCardList = handCards.subList(result.getNoneCardNum(), result.getCardNum());
		Cards laiziCards = DdzTypeUtil.createCardsCopy(laiziCardList);
		laiziCards.setResult(handCards.getResult().clone());
		DdzAnalysisResult laiziCardsResult = (DdzAnalysisResult) laiziCards.getResult();
		laiziCardsResult.collectNumber(laiziCards, term);
		
		int maxLoseValue = 0; // 寻找最大遗失的牌 让***5可以出现，但是仅一次
		for (int valueTemp = DdzCardConstant.NUMBER_2_VALUE // 从小开始
				; valueTemp >= DdzCardConstant.NUMBER_3_VALUE; valueTemp--) {
			if (result.getNoneLaziValueCounter().getValueCount(valueTemp) == 0) {
				maxLoseValue = valueTemp;
				break;
			}
		}
		int laiziCardNum = result.getLaziCardNum();
		int maxUseLaiziCardNum = MAX_USE_LAIZI_CARD_NUM < laiziCardNum ? MAX_USE_LAIZI_CARD_NUM : laiziCardNum;
		Set<Integer> exsitKeys = new HashSet<Integer>(); // 记录已经组成三带一的value
		for (int useLaiziCardNum = 0; useLaiziCardNum <= maxUseLaiziCardNum; useLaiziCardNum++) {
			if (useLaiziCardNum < MAX_USE_LAIZI_CARD_NUM) { // 用了 0.1.2.3 个癞子
				for (int valueTemp = DdzCardConstant.NUMBER_3_VALUE // 从小开始
						; valueTemp <= DdzCardConstant.NUMBER_2_VALUE; valueTemp++) {
					Cards modelCardsCopy = noneLaiziCards.clone(); // 常规牌副本
					DdzAnalysisResult modelResultCopy = (DdzAnalysisResult) modelCardsCopy.getResult();
					List<Card> useLaiziCardList = DdzTypeUtil.cloneSublistedCards(laiziCards, 0, useLaiziCardNum); // 补癞子
					int valueTempNum = modelResultCopy.getNoneLaziValueCounter().getValueCount(valueTemp);
					int needLaiziCardNum = BombTypeAnalyzer.TUPLE_SIZE - valueTempNum;
					needLaiziCardNum = needLaiziCardNum > 0 ? needLaiziCardNum : 0;
					if (needLaiziCardNum == 0) {
						List<Card> removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, BombTypeAnalyzer.TUPLE_SIZE);
						Cards tupleCards = new Cards(removedCardList);
						Cards remainCards = DdzTypeUtil.cloneCardsAndAddCardList(modelCardsCopy, useLaiziCardList);
						List<Cards> takenCardsList = repeatSelectPairCards(remainCards, 2, term);
						for (Cards takenCards : takenCardsList) {
							Cards resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
							int key = valueTemp * TUPLE_WEIGHT;
							for (Card card : takenCards) {
								key += card.getValue();
								if (((DdzCard)card).isLazi()) { // 癞子权重，区分癞子变成的5 和 原本就是5
									key += card.getValue() * LAIZI_WEIGHT;
								}
							}
							if (!exsitKeys.contains(key) && match(resultCards, term)) {
								exsitKeys.add(key);
								// 保证排序
								((DdzAnalysisResult)resultCards.getResult()).setSortFirstValue(valueTemp);
								analysize(resultCards, term);
								cardsResult.add(resultCards);
							}
						}
					} else { // 需要癞子来拼凑
						if (needLaiziCardNum == BombTypeAnalyzer.TUPLE_SIZE 
								&& valueTemp != maxLoseValue) {
							// 这里是对癞子做tuple的去重
							// 否则会出现 ****带89 既能是 3333带89 也能是 4444带89 5555带89
							continue;
						}
						if (useLaiziCardNum >= needLaiziCardNum) { // 癞子足够拼凑
							List<Card> removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, valueTempNum);
							for (int i = 0; i < needLaiziCardNum; i++) {
								DdzCard laiziCard = (DdzCard) useLaiziCardList.remove(0);
								laiziCard.changeCard(valueTemp);
								removedCardList.add(laiziCard);
							}
							for (Card laiziCard : useLaiziCardList) {
								((DdzCard)laiziCard).changeCard(laiziCard.getValue());
							}
							Cards tupleCards = new Cards(removedCardList);
							Cards remainCards = DdzTypeUtil.cloneCardsAndAddCardList(modelCardsCopy, useLaiziCardList);
							List<Cards> takenCardsList = repeatSelectPairCards(remainCards, 2, term);
							for (Cards takenCards : takenCardsList) {
								Cards resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
								int key = valueTemp * TUPLE_WEIGHT;
								for (Card card : takenCards) {
									key += card.getValue();
									if (((DdzCard)card).isLazi()) { // 癞子权重，区分癞子变成的5 和 原本就是5
										key += card.getValue() * LAIZI_WEIGHT;
									}
								}
								if (!exsitKeys.contains(key) && match(resultCards, term)) {
									exsitKeys.add(key);
									// 保证排序
									((DdzAnalysisResult)resultCards.getResult()).setSortFirstValue(valueTemp);
									analysize(resultCards, term);
									cardsResult.add(resultCards);
								}
							}
						}
					}
				}
			} else { // 用了 4个癞子
				for (int valueTemp = DdzCardConstant.NUMBER_3_VALUE // 从小开始
						; valueTemp <= DdzCardConstant.NUMBER_2_VALUE; valueTemp++) {
					Cards modelCardsCopy = laiziCards.clone(); // 常规牌补上癞子
					DdzAnalysisResult modelResultCopy = (DdzAnalysisResult) modelCardsCopy.getResult();
					if (modelResultCopy.getAllValueCounter().getValueCount(valueTemp) >= BombTypeAnalyzer.TUPLE_SIZE) {
						List<Card> removedCardList = DdzTypeUtil.cloneRemovedCards(modelCardsCopy, valueTemp, BombTypeAnalyzer.TUPLE_SIZE);
						Cards tupleCards = new Cards(removedCardList);
						List<Cards> takenCardsList = repeatSelectPairCards(modelCardsCopy, 2, term);
						for (Cards takenCards : takenCardsList) {
							Cards resultCards = DdzTypeUtil.cloneCardsAndAddCards(tupleCards, takenCards);
							for (Card card : resultCards) {
								if (((DdzCard)card).hasNotChanged()) { // 有的经过处理已经被赋值了不能再改变
									((DdzCard)card).changeCard(card.getValue());
								}
							}
							if (match(resultCards, term)) {
								// 保证排序
								((DdzAnalysisResult)resultCards.getResult()).setSortFirstValue(valueTemp);
								analysize(resultCards, term);
								cardsResult.add(resultCards);
							}
						}
					}
				}
			}
		}
		return cardsResult;
	}

	/**
	 * 在固定牌组中寻找repeat张单牌 <br>
	 * 比如在 5。5。6。7 中寻找两张单牌 5.5 5.6 5.7 6.7   注意这里已经去重了 6.7 和 7.6 不会同时出现 
	 * 
	 * @param cards
	 * @param repeat
	 * @param term
	 * @param onlyMaxValue
	 * @return
	 */
	public List<Cards> repeatSelectPairCards(Cards cards, int repeat, AbstractSuitTerm term) {
		Cards modelCards = DdzTypeUtil.cloneCardsAndAddCardList(cards, null); // 常规牌补上癞子
		DdzAnalysisResult modelResult = (DdzAnalysisResult) modelCards.getResult();
		modelResult.collectNumber(modelCards, term);
		if (modelResult.getCardNum() < 2 * repeat) { // 数量不足
			return new ArrayList<Cards>();
		}
		List<Cards> resultCardsList = pairTypeAnalyzer.listPossibleCards(modelCards, term); // 记录最终结果
		if (resultCardsList.size() != 0) {
			for (int i = 1; i < repeat; i++) { // 上面已经获取了一次了
				Set<Integer> exsitKeys = new HashSet<Integer>(); // 每一步都去重
				List<Cards> currentCardsList = new LinkedList<Cards>(resultCardsList);
				resultCardsList.clear(); // 清空上一步的结果
				for (Cards preCards : currentCardsList) {
					Cards remainCards = DdzTypeUtil.cloneCardsAndRemoveCards(modelCards, preCards);
					List<Cards> nextCardsList = pairTypeAnalyzer.listPossibleCards(remainCards, term);
					for (Cards nextCards : nextCardsList) {
						Cards combinedCards = DdzTypeUtil.cloneCardsAndAddCards(preCards, nextCards);
						int key = 0;
						for (Card card : combinedCards) {
							key += card.getValue();
							if (((DdzCard)card).isLazi()) { // 癞子权重，区分癞子变成的5 和 原本就是5
								key += LAIZI_WEIGHT;
							}
						}
						if (!exsitKeys.contains(key)) {
							exsitKeys.add(key);
							resultCardsList.add(combinedCards);
						}
					}
				}
			}
		}
		return resultCardsList;
	}
}
